﻿function Diagram(domEl) {
    this.readOnlySvgD3Object = domEl;
    this._domEl = domEl;
    var that = this;

    this._elementList = [];
    this._selectedElement = null;
    this._selectedOffset = null;
    this.addElement = function (el) {
        this._elementList.push(el);
        el.updateLayout();
    }

    this._domEl.on("mousedown", function () {
        var mousePos = { x: d3.event.x, y: d3.event.y };
        for (var i = that._elementList.length - 1; i >= 0; i--) {
            if (that._elementList[i].hitTest != undefined) {
                var hitResult = that._elementList[i].hitTest(mousePos);
                if (hitResult.isHit) {
                    that._selectedElement = that._elementList[i];
                    that._selectedOffset = { x: hitResult.offsetX, y: hitResult.offsetY };
                    break;
                }
            }
        }
    })

    this._domEl.on("mousemove", function () {
        if (that._selectedElement != null) {
            var mousePos = { x: d3.event.x + that._selectedOffset.x, y: d3.event.y + that._selectedOffset.y };
            that._selectedElement.setActualPosition(mousePos);
            that._selectedElement.updateLayout();
        }
    })

    this._domEl.on("mouseup", function () { that._selectedElement = null; })
}

function Element() {
    this.updateLayout = function () { }
    this.getDomEl = function () { }
    this.getPosition = function () { };
    this.getSize = function () { };
    this.setPosition = function (pos) { };
    this.setSize = function (size) { };
    this.logFlag = true;

    this.hide = function () {
        this._domEl.attr("display", "none");
    }
}

function BaseNode(domEl, position, size) {
    this._domEl = domEl;
    Element.apply(this, []);

    this._position = position;
    this._size = size;
    this._parent = null;

    this.getDomEl = function () {
        return this._domEl;
    }

    this._linkList = new Array();

    this.addLink = function (link) {
        this._linkList.push(link);
    }

    this.setPosition = function (pos) {
        this._position = pos;
    }

    this.setSize = function (size) {
        this._size = size;
    }

    this.getSize = function () {
        return this._size;
    }

    this.updateLayout = function () {
        this.onUpdateLayout();
        for (var i = 0; i < this._linkList.length; i++) {
            this._linkList[i].updateLayout();
        }
    }

    this.onUpdateLayout = function () { };
    this.hitTest = function (pos) { };
    this.getActualPosition = function () {
        var pos = { x: parseInt(this._position.x), y: parseInt(this._position.y) };
        var parent = this._parent;
        while (parent != null) {
            pos.x += parseInt(parent._position.x);
            pos.y += parseInt(parent._position.y);
            parent = parent._parent;
        }
        return pos;
    }
    this.setActualPosition = function (actualPos) {
        var parent = this._parent;
        if (parent == null) {
            this._position = actualPos;
        }
        else {
            var pactual = this._parent.getActualPosition();
            if (actualPos.x >= pactual.x
                && actualPos.x + this._size.w <= pactual.x + this._parent.getSize().w
                && actualPos.y >= pactual.y
                && actualPos.y + this._size.h <= pactual.y + this._parent.getSize().h) {
                var pos = { x: actualPos.x, y: actualPos.y };
                while (parent != null) {
                    pos.x -= parent._position.x;
                    pos.y -= parent._position.y;
                    parent = parent._parent;
                }

                this._position.x = pos.x;
                this._position.y = pos.y;
            }
        }
    }
}

function BaseLine(domEl) {
    BaseNode.apply(this, [domEl, null, null]);
    this.getActualPosition = function () {
        
        var pos = { x: parseInt(this._position.x), y: parseInt(this._position.y) };
        var parent = this._parent;
        while (parent != null) {
            pos.x += parseInt(parent._position.x);
            pos.y += parseInt(parent._position.y);
            parent = parent._parent;
        }
        return pos;
    }
    this.setActualPosition = function (actualPos) {
        var parent = this._parent;
        if (parent == null) {
            this._position = actualPos;
        }
        else {
            var pactual = this._parent.getActualPosition();
            if (actualPos.x >= pactual.x
                && actualPos.x + this._size.w <= pactual.x + this._parent.getSize().w
                && actualPos.y >= pactual.y
                && actualPos.y + this._size.h <= pactual.y + this._parent.getSize().h) {
                var pos = { x: actualPos.x, y: actualPos.y };
                while (parent != null) {
                    pos.x -= parent._position.x;
                    pos.y -= parent._position.y;
                    parent = parent._parent;
                }

                this._position.x = pos.x;
                this._position.y = pos.y;
            }
        }
    }
}